/*-
 * Copyright (c) 2009-2010 Alexander Egorenkov <egorenar@gmail.com>
 * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#ifdef RT2860_DEBUG

enum
{
	RT2860_DEBUG_EEPROM =	0x00000001,
	RT2860_DEBUG_RX =	0x00000002,
	RT2860_DEBUG_TX =	0x00000004,
	RT2860_DEBUG_INTR =	0x00000008,
	RT2860_DEBUG_STATE =	0x00000010,
	RT2860_DEBUG_CHAN =	0x00000020,
	RT2860_DEBUG_NODE =	0x00000040,
	RT2860_DEBUG_KEY =	0x00000080,
	RT2860_DEBUG_PROT =	0x00000100,
	RT2860_DEBUG_WME =	0x00000200,
	RT2860_DEBUG_BEACON =	0x00000400,
	RT2860_DEBUG_BA =	0x00000800,
	RT2860_DEBUG_STATS =	0x00001000,
	RT2860_DEBUG_RATE =	0x00002000,
	RT2860_DEBUG_PERIODIC =	0x00004000,
	RT2860_DEBUG_WATCHDOG =	0x00008000,
	RT2860_DEBUG_RX_CRYPT = 0x00010000,
	RT2860_DEBUG_TX_CRYPT = 0x00020000,
	RT2860_DEBUG_ANY = 0xffffffff
};

#define RT2860_DPRINTF(sc, m, ...)		\
    do { if ((sc)->debug & (m)) 		\
    device_printf(sc->sc_dev, __VA_ARGS__); } while (0)

#else

#define RT2860_DPRINTF(sc, m, ...)

#endif /* #ifdef RT2860_DEBUG */

#define RT2860_AMRR_MIN_SUCCESS_THRESHOLD	 		1
#define RT2860_AMRR_MAX_SUCCESS_THRESHOLD			15

struct rt2860_amrr
{
	int ntxpath;

	unsigned int min_success_threshold;
	unsigned int max_success_threshold;

	int	interval;
};

struct rt2860_amrr_node
{
	struct rt2860_amrr *amrr;

	int	rate_index;

	int	ticks;

	unsigned int txcnt;
	unsigned int success;
	unsigned int success_threshold;
	unsigned int recovery;
	unsigned int retrycnt;
};

#define RT2860_SOFTC_LOCK(sc)				mtx_lock(&(sc)->sc_mtx)
#define RT2860_SOFTC_UNLOCK(sc)				\
		mtx_unlock(&(sc)->sc_mtx)
#define	RT2860_SOFTC_ASSERT_LOCKED(sc)			\
		mtx_assert(&(sc)->sc_mtx, MA_OWNED)

#define RT2860_SOFTC_TX_RING_LOCK(ring)			mtx_lock(&(ring)->lock)
#define RT2860_SOFTC_TX_RING_UNLOCK(ring)		\
		mtx_unlock(&(ring)->lock)
#define	RT2860_SOFTC_TX_RING_ASSERT_LOCKED(ring)	\
		mtx_assert(&(ring)->lock, MA_OWNED)

#define RT2860_SOFTC_FLAGS_UCODE_LOADED			(1 << 0)
#define RT2860_SOFTC_LED_OFF_COUNT			3
#define RT2860_SOFTC_RSSI_OFF_COUNT			3
#define RT2860_SOFTC_LNA_GAIN_COUNT			4
#define RT2860_SOFTC_TXPOW_COUNT			50
#define RT2860_SOFTC_TXPOW_RATE_COUNT			5
#define RT2860_SOFTC_TSSI_COUNT				9
#define RT2860_SOFTC_BBP_EEPROM_COUNT			8
#define RT2860_SOFTC_RSSI_COUNT				3
#define RT2860_SOFTC_STAID_COUNT			64
#define RT2860_SOFTC_TX_RING_COUNT			6
#define RT2860_SOFTC_RX_RING_DATA_COUNT			128
#define RT2860_SOFTC_MAX_SCATTER			10
#define RT2860_SOFTC_TX_RING_DATA_COUNT			256
#define RT2860_SOFTC_TX_RING_DESC_COUNT					\
	(RT2860_SOFTC_TX_RING_DATA_COUNT * RT2860_SOFTC_MAX_SCATTER)

#define RT2860_SOFTC_RX_RADIOTAP_PRESENT				\
	((1 << IEEE80211_RADIOTAP_FLAGS) |				\
	 (1 << IEEE80211_RADIOTAP_RATE) |				\
	 (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |			\
	 (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) |			\
	 (1 << IEEE80211_RADIOTAP_ANTENNA) |				\
	 (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) |			\
	 (1 << IEEE80211_RADIOTAP_XCHANNEL))

#define RT2860_SOFTC_TX_RADIOTAP_PRESENT				\
	((1 << IEEE80211_RADIOTAP_FLAGS) |				\
	 (1 << IEEE80211_RADIOTAP_RATE) |				\
	 (1 << IEEE80211_RADIOTAP_XCHANNEL))

struct rt2860_softc_rx_data
{
	bus_dmamap_t dma_map;
	struct mbuf *m;
};

struct rt2860_softc_rx_ring
{
	bus_dma_tag_t desc_dma_tag;
	bus_dmamap_t desc_dma_map;
	bus_addr_t desc_phys_addr;
	struct rt2860_rxd *desc;
	bus_dma_tag_t data_dma_tag;
	bus_dmamap_t spare_dma_map;
	struct rt2860_softc_rx_data data[RT2860_SOFTC_RX_RING_DATA_COUNT];
	int cur;
};

struct rt2860_softc_tx_data
{
	bus_dmamap_t dma_map;
	struct ieee80211_node *ni;
	struct mbuf *m;
};

struct rt2860_softc_tx_ring
{
	struct mtx lock;
	bus_dma_tag_t desc_dma_tag;
	bus_dmamap_t desc_dma_map;
	bus_addr_t desc_phys_addr;
	struct rt2860_txd *desc;
	int desc_queued;
	int desc_cur;
	int desc_next;
	bus_dma_tag_t seg0_dma_tag;
	bus_dmamap_t seg0_dma_map;
	bus_addr_t seg0_phys_addr;
	uint8_t *seg0;
	bus_dma_tag_t data_dma_tag;
	struct rt2860_softc_tx_data data[RT2860_SOFTC_TX_RING_DATA_COUNT];
	int data_queued;
	int data_cur;
	int data_next;
	int qid;
};

struct rt2860_softc_node
{
	struct ieee80211_node ni;

	uint8_t staid;

	uint8_t last_rssi[RT2860_SOFTC_RSSI_COUNT];
	int8_t last_rssi_dbm[RT2860_SOFTC_RSSI_COUNT];
};

struct rt2860_softc_vap
{
	struct ieee80211vap	vap;

	struct ieee80211_beacon_offsets beacon_offsets;
	struct mbuf *beacon_mbuf;
	struct rt2860_amrr amrr;

	int	(*newstate)(struct ieee80211vap *vap,
		enum ieee80211_state nstate, int arg);
};

struct rt2860_softc_rx_radiotap_header
{
	struct ieee80211_radiotap_header ihdr;
	uint8_t	flags;
	uint8_t	rate;
	int8_t dbm_antsignal;
	int8_t dbm_antnoise;
	uint8_t	antenna;
	uint8_t	antsignal;
	uint8_t pad[2];
	uint32_t chan_flags;
	uint16_t chan_freq;
	uint8_t chan_ieee;
	int8_t chan_maxpow;
} __packed;

struct rt2860_softc_tx_radiotap_header
{
	struct ieee80211_radiotap_header ihdr;
	uint8_t flags;
	uint8_t	rate;
	uint8_t pad[2];
	uint32_t chan_flags;
	uint16_t chan_freq;
	uint8_t chan_ieee;
	int8_t chan_maxpow;
} __packed;

struct rt2860_softc
{
	struct ifnet			*sc_ifp;
	device_t			sc_dev;
	bus_space_tag_t			sc_st;
	bus_space_handle_t		sc_sh;

	struct mtx			sc_mtx;

	struct callout			watchdog_ch;

	int				sc_tx_timer;
	int                             sc_invalid;
	int				sc_debug;
/*
 * The same in both up to here
 * ------------------------------------------------
 */
	int			id;
	uint32_t 		flags;
	int			mem_rid; /* XXX: bus glue handle res */
	struct resource		*mem;

	int			irq_rid;
	struct resource 	*irq;
	void 			*irqh;

	int			if_flags;

	int			nvaps;
	int			napvaps;
	int nadhocvaps;
	int nstavaps;
	int nwdsvaps;

	void (*node_cleanup)(struct ieee80211_node *ni);

	int (*recv_action)(struct ieee80211_node *ni,
		const struct ieee80211_frame *wh,
		const uint8_t *frm, const uint8_t *efrm);

	int (*send_action)(struct ieee80211_node *ni,
		int cat, int act, void *sa);

	int (*addba_response)(struct ieee80211_node *ni,
		struct ieee80211_tx_ampdu *tap,
		int status, int baparamset, int batimeout);

	void (*addba_stop)(struct ieee80211_node *ni,
		struct ieee80211_tx_ampdu *tap);

	int (*ampdu_rx_start)(struct ieee80211_node *ni,
		struct ieee80211_rx_ampdu *rap,
		int baparamset, int batimeout, int baseqctl);

	void (*ampdu_rx_stop)(struct ieee80211_node *ni,
		struct ieee80211_rx_ampdu *rap);

	struct rt2860_amrr_node amrr_node[RT2860_SOFTC_STAID_COUNT];

	uint32_t mac_rev;
	uint8_t eeprom_addr_num;
	uint16_t eeprom_rev;
	uint8_t rf_rev;

	uint8_t mac_addr[IEEE80211_ADDR_LEN];

	uint8_t ntxpath;
	uint8_t nrxpath;

	int hw_radio_cntl;
	int tx_agc_cntl;
	int ext_lna_2ghz;
	int ext_lna_5ghz;

	uint8_t country_2ghz;
	uint8_t country_5ghz;

	uint8_t rf_freq_off;

	uint8_t led_cntl;
	uint16_t led_off[RT2860_SOFTC_LED_OFF_COUNT];

	int8_t rssi_off_2ghz[RT2860_SOFTC_RSSI_OFF_COUNT];
	int8_t rssi_off_5ghz[RT2860_SOFTC_RSSI_OFF_COUNT];

	int8_t lna_gain[RT2860_SOFTC_LNA_GAIN_COUNT];

	int8_t txpow1[RT2860_SOFTC_TXPOW_COUNT];
	int8_t txpow2[RT2860_SOFTC_TXPOW_COUNT];

	int8_t txpow_rate_delta_2ghz;
	int8_t txpow_rate_delta_5ghz;
	uint32_t txpow_rate_20mhz[RT2860_SOFTC_TXPOW_RATE_COUNT];
	uint32_t txpow_rate_40mhz_2ghz[RT2860_SOFTC_TXPOW_RATE_COUNT];
	uint32_t txpow_rate_40mhz_5ghz[RT2860_SOFTC_TXPOW_RATE_COUNT];

	int tx_agc_cntl_2ghz;
	int tx_agc_cntl_5ghz;

	uint8_t tssi_2ghz[RT2860_SOFTC_TSSI_COUNT];
	uint8_t tssi_step_2ghz;
	uint8_t tssi_5ghz[RT2860_SOFTC_TSSI_COUNT];
	uint8_t tssi_step_5ghz;

	struct
	{
		uint8_t	val;
		uint8_t	reg;
	} __packed bbp_eeprom[RT2860_SOFTC_BBP_EEPROM_COUNT], rf[10];

	uint16_t powersave_level;

	uint8_t staid_mask[RT2860_SOFTC_STAID_COUNT / NBBY];

	uint32_t intr_enable_mask;
	uint32_t intr_disable_mask;
	uint32_t intr_pending_mask;

	struct task rx_done_task;
	int rx_process_limit;

	struct task tx_done_task;

	struct task fifo_sta_full_task;

	struct task periodic_task;
	struct callout periodic_ch;
	unsigned long periodic_round;

	struct taskqueue *taskqueue;

	struct rt2860_softc_rx_ring rx_ring;

	struct rt2860_softc_tx_ring tx_ring[RT2860_SOFTC_TX_RING_COUNT];
	int tx_ring_mgtqid;

	struct callout tx_watchdog_ch;
	int tx_timer;

	struct rt2860_softc_rx_radiotap_header rxtap;
	struct rt2860_softc_tx_radiotap_header txtap;

	/* statistic counters */

	unsigned long interrupts;
	unsigned long tx_coherent_interrupts;
	unsigned long rx_coherent_interrupts;
	unsigned long txrx_coherent_interrupts;
	unsigned long fifo_sta_full_interrupts;
	unsigned long rx_interrupts;
	unsigned long tx_interrupts[RT2860_SOFTC_TX_RING_COUNT];

	unsigned long tx_data_queue_full[RT2860_SOFTC_TX_RING_COUNT];

	unsigned long tx_watchdog_timeouts;

	unsigned long tx_defrag_packets;

	unsigned long no_tx_desc_avail;

	unsigned long rx_mbuf_alloc_errors;
	unsigned long rx_mbuf_dmamap_errors;

	unsigned long tx_queue_not_empty[2];

	unsigned long tx_beacons;
	unsigned long tx_noretryok;
	unsigned long tx_retryok;
	unsigned long tx_failed;
	unsigned long tx_underflows;
	unsigned long tx_zerolen;
	unsigned long tx_nonagg;
	unsigned long tx_agg;
	unsigned long tx_ampdu;
	unsigned long tx_mpdu_zero_density;
	unsigned long tx_ampdu_sessions;

	unsigned long rx_packets;
	unsigned long rx_ampdu;
	unsigned long rx_ampdu_retries;
	unsigned long rx_mpdu_zero_density;
	unsigned long rx_ampdu_sessions;
	unsigned long rx_amsdu;
	unsigned long rx_crc_errors;
	unsigned long rx_phy_errors;
	unsigned long rx_false_ccas;
	unsigned long rx_plcp_errors;
	unsigned long rx_dup_packets;
	unsigned long rx_fifo_overflows;
	unsigned long rx_cipher_no_errors;
	unsigned long rx_cipher_icv_errors;
	unsigned long rx_cipher_mic_errors;
	unsigned long rx_cipher_invalid_key_errors;

	int tx_stbc;

	uint8_t rf24_20mhz;
	uint8_t	rf24_40mhz;
	uint8_t	patch_dac;
	uint8_t	txmixgain_2ghz;
	uint8_t	txmixgain_5ghz;

#ifdef RT2860_DEBUG
	int debug;
#endif
};

/*
 * RT2860_EEPROM_NIC_CONFIG flags
 */
#define RT2860_EEPROM_EXT_LNA_5GHZ			(1 << 3)
#define RT2860_EEPROM_EXT_LNA_2GHZ			(1 << 2)
#define RT2860_EEPROM_TX_AGC_CNTL			(1 << 1)
#define RT2860_EEPROM_HW_RADIO_CNTL			(1 << 0)

#define RT2860_EEPROM_LED_POLARITY			(1 << 7)
#define RT2860_EEPROM_LED_MODE_MASK			0x7f

#define RT2860_EEPROM_LED_CNTL_DEFAULT			0x01
#define RT2860_EEPROM_LED1_OFF_DEFAULT			0x5555
#define RT2860_EEPROM_LED2_OFF_DEFAULT			0x2221
#define RT2860_EEPROM_LED3_OFF_DEFAULT			0xa9f8

#define RT2860_EEPROM_RSSI_OFF_MIN			-10
#define RT2860_EEPROM_RSSI_OFF_MAX			10

#define RT2860_EEPROM_TXPOW_2GHZ_MIN			0
#define RT2860_EEPROM_TXPOW_2GHZ_MAX			31
#define RT2860_EEPROM_TXPOW_2GHZ_DEFAULT		5
#define RT2860_EEPROM_TXPOW_5GHZ_MIN			-7
#define RT2860_EEPROM_TXPOW_5GHZ_MAX			15
#define RT2860_EEPROM_TXPOW_5GHZ_DEFAULT		5

#define RT2860_IO_MCU_CMD_SLEEP				0x30
#define RT2860_IO_MCU_CMD_WAKEUP			0x31
#define RT2860_IO_MCU_CMD_RADIOOFF			0x35
#define RT2860_IO_MCU_CMD_LEDS				0x50
#define RT2860_IO_MCU_CMD_LED_BRIGHTNESS		0x51
#define RT2860_IO_MCU_CMD_LED1				0x52
#define RT2860_IO_MCU_CMD_LED2				0x53
#define RT2860_IO_MCU_CMD_LED3				0x54
#define RT2860_IO_MCU_CMD_BOOT				0x72
#define RT2860_IO_MCU_CMD_BBP				0x80
#define RT2860_IO_MCU_CMD_POWERSAVE_LEVEL		0x83

#define RT2860_LED_CMD_RADIO_OFF			0
#define RT2860_LED_CMD_RADIO_ON				(1 << 5)
#define RT2860_LED_CMD_LINK_2GHZ			(1 << 6)
#define RT2860_LED_CMD_LINK_5GHZ			(1 << 7)

/*
 * Global function prototypes, used in bus depended interfaces
 */

int rt2860_attach(device_t, int);
int rt2860_detach(void *);
void rt2860_shutdown(void *);
void rt2860_suspend(void *);
void rt2860_resume(void *);
void rt2860_intr(void *arg);
